package object3D;

import context.*;

import geometry3D.Point3D;
import geometry3D.Transform;
import model2D.Model2D;
import geometry2D.Projection2D;
import object2D.BlockProjection;

import java.awt.Color;
import java.util.Vector;
import java.util.Enumeration;

// Java 3D
import javax.media.j3d.Group;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.Transform3D;
import javax.media.j3d.Appearance;
import com.sun.j3d.utils.geometry.Box;
import javax.vecmath.Vector3f;

import org.json.JSONException;


// ********************************************************************
// *** CLASS: Block
// ********************************************************************
public class Block extends Object3D implements Context.Constants
{ //private static final boolean DEBUG=true; // Overriding Context.Constants.DEBUG
    
  public Vector<Block> extras; // Extra object attached to this object
  
  protected double rotateX=0; // Clockwise rotation in radians
  protected double rotateY=0; // Clockwise rotation in radians
  protected double rotateZ=0; // Clockwise rotation in radians
  public void setRotate(double rx,double ry,double rz)
  { rotateX=rx; rotateY=ry; rotateZ=rz; }
  
      
  // ***************************************************************************
  // *** CONSTRUCTOR: Block
  // ***************************************************************************
  public Block(String ident,Point3D p0,double width,double height,double depth)
  { super(ident,p0,width,height,depth);
    this.extras=new Vector<Block>();
  }
  
  // ***************************************************************************
  // *** METHOD: contains
  // ***************************************************************************
  public boolean contains(Point3D p)
  { if( (p.x>=p0.x) & (p.x<=(p0.x+width)) )
    { if( (p.y>=p0.y) & (p.y<=(p0.x+height)) )
      { if( (p.z>=p0.z) & (p.z<=(p0.z+depth)) ) return(true); }
    }
    return(false);
  }
  
  // ***************************************************************************
  // *** METHOD: addExtra
  // ***************************************************************************
  public void addExtra(Block extra)
  { this.extras.add(extra); }  
  
    
  // ***************************************************************************
  // *** METHOD: getExtra
  // ***************************************************************************
  public Block getExtra(String ident)
  { for(Enumeration<Block> e=extras.elements();e.hasMoreElements();)
    { Block extra=e.nextElement();
      if(extra.ident.equals(ident)) return(extra);
    }
    return(null);
  }
  
  // ***************************************************************************
  // *** METHOD: getModel3D
  // ***************************************************************************
  public /*abstract*/ Group getModel3D(Appearance appearance)
  { TransformGroup tg=new TransformGroup();
    Transform3D transform=new Transform3D();
    double x=p0.x+width/2;
    double y=p0.y+height/2;
    double z=p0.z+depth/2;
    transform.setTranslation(new Vector3f((float)x,(float)y,(float)z));
    transform=Transform.rotate(transform,rotateX,rotateY,rotateZ);
    tg.setTransform(transform);
    Box box=new Box((float)width/2,(float)height/2,(float)depth/2,appearance);
    tg.addChild(box);
    return(tg);
  }  
  
  // ***************************************************************************
  // *** METHOD: addProjection  (2D)
  // ***************************************************************************
  // 3D ==> 2D projections the XZ, XY or ZY-plane
  public void addProjection(Model2D objectModel,int type,int direction,Color color,float opacity)
  throws JSONException
  { objectModel.addChild(new BlockProjection(objectModel,this,type,direction,color,opacity)); }
  
  // ***************************************************************************
  // *** METHOD: addExtraProjection
  // ***************************************************************************
  public void addExtraProjection(Model2D objectModel,int type,int direction,Color color,float opacity)
  throws JSONException
  { for(Enumeration<Block> e=extras.elements();e.hasMoreElements();)
    { Block extra=e.nextElement();
      extra.addProjection(objectModel,type,direction,color,opacity);
    }
  }

  // ***************************************************************************
  // *** METHOD: toProjection2D -- NOTE: See also: Point3D.toPoint2D
  // ***************************************************************************
  // 3D ==> 2D projections
  public Projection2D toProjection2D(int direction)
  { double x1=0,y1=0,w1=0,h1=0;
    switch(direction)
    { case ABOVE: // Horisontial projection seen from above onto the XZ-plane
           x1=this.p0.x; y1=this.p0.z; w1=this.width; h1=this.depth;
           break;
      case BELOW: // Horisontial projection seen from below onto the XZ-plane
           x1=this.p0.x; y1= -this.p0.z-this.height; w1=this.width; h1=this.depth;
           break; 
      case SOUTH: // Vertical projection seen from south onto the XY-plane
           x1=this.p0.x; y1= -this.p0.y-this.height; w1=this.width; h1=this.height;
           break; 
      case NORTH: // Vertical projection seen from north onto the XY-plane
           x1= -this.p0.x-this.width; y1= -this.p0.y-this.height; w1=this.width; h1=this.height;
           break;
      case EAST: // Vertical projection seen from east onto the ZY-plane
           x1= -this.p0.z-this.depth; y1= -this.p0.y-this.height; w1=this.depth; h1=this.height;
           break;
      case WEST: // Vertical projection seen from west onto the ZY-plane
           x1=this.p0.z; y1= -this.p0.y-this.height; w1=this.depth; h1=this.height;
           break;
    }       
    return(new Projection2D(x1,y1,w1,h1));
  }

}  